package io.gitee.mingbaobaba.security.plugin.jpa.repository;

import io.gitee.mingbaobaba.security.core.constants.SecurityConstant;
import io.gitee.mingbaobaba.security.core.domain.SecuritySession;
import io.gitee.mingbaobaba.security.core.domain.SecurityToken;
import io.gitee.mingbaobaba.security.core.repository.SecurityRepository;
import io.gitee.mingbaobaba.security.core.utils.DateUtil;
import io.gitee.mingbaobaba.security.core.utils.JsonUtil;
import io.gitee.mingbaobaba.security.plugin.jpa.entity.SecuritySessionEntity;
import io.gitee.mingbaobaba.security.plugin.jpa.entity.SecurityTokenEntity;
import org.springframework.beans.factory.annotation.Autowired;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>jpa存储实现</p>
 *
 * @author yingsheng.ye
 * @version 1.0.0
 * @since 2023/9/14 4:35
 */
public class SecurityJpaRepository implements SecurityRepository {

    @Autowired
    private SecuritySessionServiceRepository securitySessionRepository;

    @Autowired
    private SecurityTokenServiceRepository securityTokenRepository;

    @Override
    public SecuritySession getSecuritySessionByLoginId(String loginId) {
        Optional<SecuritySessionEntity> optional = securitySessionRepository.findById(loginId);
        if (!optional.isPresent()) {
            return null;
        }
        SecuritySessionEntity securitySessionEntity = optional.get();
        //验证是否已超时
        if (securitySessionEntity.getCreateTime().plusSeconds(securitySessionEntity.getTimeout()).isBefore(LocalDateTime.now())) {
            //已超时,删除信息
            removeSecuritySessionByLoginId(securitySessionEntity.getLoginId());
            return null;
        }
        SecuritySession securitySession = JsonUtil.jsonStrToObject(securitySessionEntity.getSessionData(), SecuritySession.class);
        securitySession.setVersion(securitySessionEntity.getVersion());
        return securitySession;
    }

    @Override
    public Long getSessionTimeoutByLoginId(String loginId) {
        Optional<SecuritySessionEntity> optional = securitySessionRepository.findById(loginId);
        if (!optional.isPresent()) {
            return 0L;
        }
        SecuritySessionEntity securitySessionEntity = optional.get();

        if (SecurityConstant.NON_EXPIRING.equals(securitySessionEntity.getTimeout())) {
            return SecurityConstant.NON_EXPIRING;
        }
        //计算超时时间
        long timeout = securitySessionEntity.getCreateTime().plusSeconds(securitySessionEntity.getTimeout())
                .toEpochSecond(ZoneOffset.ofHours(8)) - LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8));
        return timeout > 0 ? timeout : 0L;
    }

    @Override
    public boolean saveSecuritySession(SecuritySession session) {
        SecuritySessionEntity securitySessionEntity = new SecuritySessionEntity();
        securitySessionEntity.setLoginId(session.getLoginId());
        securitySessionEntity.setTimeout(session.getTimeout());
        securitySessionEntity.setCreateTime(DateUtil.strToLocalDateTime.apply(session.getCreateTime()));
        securitySessionEntity.setUpdateTime(LocalDateTime.now());
        securitySessionEntity.setVersion(session.getVersion());
        securitySessionEntity.setSessionData(JsonUtil.objectToJsonStr(session));
        securitySessionRepository.save(securitySessionEntity);
        return true;
    }

    @Override
    public boolean removeSecuritySessionByLoginId(String loginId) {
        securitySessionRepository.deleteById(loginId);
        return true;
    }

    @Override
    public SecurityToken getSecurityTokenByTokenValue(String tokenValue) {
        Optional<SecurityTokenEntity> optional = securityTokenRepository.findById(tokenValue);
        if (!optional.isPresent()) {
            return null;
        }
        SecurityTokenEntity securityTokenEntity = optional.get();
        return JsonUtil.jsonStrToObject(securityTokenEntity.getTokenData(), SecurityToken.class);
    }

    @Override
    public String getActivityTimeByTokenValue(String tokenValue) {
        Optional<SecurityTokenEntity> optional = securityTokenRepository.findById(tokenValue);
        if (!optional.isPresent()) {
            return null;
        }
        SecurityTokenEntity securityTokenEntity = optional.get();
        return DateUtil.localDateTimeToStr.apply(securityTokenEntity.getActivityTime());
    }

    @Override
    public Long getTokenTimeOutByTokenValue(String tokenValue) {
        Optional<SecurityTokenEntity> optional = securityTokenRepository.findById(tokenValue);
        if (!optional.isPresent()) {
            return null;
        }
        SecurityTokenEntity securityTokenEntity = optional.get();
        if (SecurityConstant.NON_EXPIRING.equals(securityTokenEntity.getTimeout())) {
            return SecurityConstant.NON_EXPIRING;
        }
        //计算超时时间
        long timeout = securityTokenEntity.getCreateTime().plusSeconds(securityTokenEntity.getTimeout())
                .toEpochSecond(ZoneOffset.ofHours(8)) - LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8));
        return timeout > 0 ? timeout : 0L;
    }

    @Override
    public Long getTokenActivityTimeOutByTokenValue(String tokenValue) {
        Optional<SecurityTokenEntity> optional = securityTokenRepository.findById(tokenValue);
        if (!optional.isPresent()) {
            return null;
        }
        SecurityTokenEntity securityTokenEntity = optional.get();
        if (SecurityConstant.NON_EXPIRING.equals(securityTokenEntity.getActivityTimeout())) {
            return SecurityConstant.NON_EXPIRING;
        }
        //计算超时时间
        long timeout = securityTokenEntity.getActivityTime().plusSeconds(securityTokenEntity.getActivityTimeout())
                .toEpochSecond(ZoneOffset.ofHours(8)) - LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8));
        return timeout > 0 ? timeout : 0L;
    }

    @Override
    public boolean saveToken(SecurityToken securityToken) {
        SecurityTokenEntity securityTokenEntity = new SecurityTokenEntity();
        securityTokenEntity.setToken(securityToken.getToken());
        securityTokenEntity.setLoginId(securityToken.getLoginId());
        securityTokenEntity.setTimeout(securityToken.getTimeout());
        securityTokenEntity.setActivityTime(LocalDateTime.now());
        securityTokenEntity.setActivityTimeout(securityToken.getActivityTimeout());
        securityTokenEntity.setUpdateTime(LocalDateTime.now());
        securityTokenEntity.setTokenData(JsonUtil.objectToJsonStr(securityToken));
        Optional<SecurityTokenEntity> optional = securityTokenRepository.findById(securityToken.getToken());
        if (optional.isPresent()) {
            securityTokenEntity.setCreateTime(optional.get().getCreateTime());
        } else {
            securityTokenEntity.setCreateTime(LocalDateTime.now());
        }
        securityTokenRepository.save(securityTokenEntity);
        return true;
    }

    @Override
    public boolean removeTokenByTokenValue(String tokenValue) {
        securityTokenRepository.deleteById(tokenValue);
        return true;
    }

    @Override
    public boolean renewalTokenByTokenValue(String tokenValue) {
        Optional<SecurityTokenEntity> optional = securityTokenRepository.findById(tokenValue);
        if (!optional.isPresent()) {
            return false;
        }
        SecurityTokenEntity securityTokenEntity = optional.get();
        securityTokenEntity.setActivityTime(LocalDateTime.now());
        securityTokenEntity.setUpdateTime(LocalDateTime.now());
        securityTokenRepository.save(securityTokenEntity);
        return true;
    }

    @Override
    public List<String> queryTokenList(String tokenValue, boolean sortedDesc) {
        List<SecurityTokenEntity> securityTokenEntityList = securityTokenRepository.findByTokenLike(tokenValue);
        if (null == securityTokenEntityList || securityTokenEntityList.isEmpty()) {
            return new ArrayList<>();
        }
        List<String> list = securityTokenEntityList.stream().map(SecurityTokenEntity::getToken)
                .collect(Collectors.toList());
        if (Boolean.TRUE.equals(sortedDesc)) {
            Collections.reverse(list);
        }
        return list;
    }
}
